// Promise源码
/** 需求分析
1、Promise是一个类， 执行类的时候需要有执行器， 执行器的作用是立即执行Promise
2、Promise 有三种状态
    pending：等待
    fulfilled： 成功
    rejected：失败
   三个状态的改变：
    pending -> fulfilled
    pending -> rejected
3、需定义revolve 和 reject函数，用来更改状态
    resolve： fulfilled
    reject： rejected
4、回调函数then(revolve，reject)
    - 判断状态并调用相应的revolve和reject函数
    - 该方法可以被链式调用， 下一个then方法的回调函数拿到的值是上一个then方法的回调函数返回值
    - then()的回调函数不能返回当前promise实例
    - then方法的参数是可选的，所以当then中没有调用的参数，依旧需要将值依次向下传递
5、异常捕获：
    - 执行器
    - then方法中各个状态捕获异常，并且错误需要在下一个then方法调用前捕获到
6、静态方法all
    - 接收数组作为参数
    - 在执行的过程中只要有一个失败，就返回错误原因
    - 只有所有promise都执行完后，才以数组的形式返回成功
7、静态方法reslove
    - resolve将给定的值转化为promise对象， 即返回值是一个promise对象
9、回调方法finally
    - 无论promise的状态是成功的还是失败的，finally方法都会被执行一次
    - 可在finally方法后面链式调用then方法来拿到当前promise对象最终返回的结果
    - 允许finally返回promise或普通值， 如果返回中有异步的情况，需要等待异步任务执行后才向then传递返回值
10、回调方法catch
    - 处理当前promise对象最终状态为失败的情况
    - 返回错误原因
*/

const { reject } = require("lodash")
const { resolve } = require("../3-promise-origin/code/myPromise")


// 定义状态常量
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected'// 失败


class MyPromise{
     // executor执行器， 需立即执行, 且需要对异常进行捕获
    constructor (executor){
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
        
    }

    // 状态变量, 初始状态是pending
    status = PENDING

    // 成功的值
    value = undefined
    // 失败原因的值
    reason = undefined
    // 成功的回调, 多次调用promise对象时使用， 所以初始状态为一个数组
    successCallback = []
    // 失败的回调
    failCallback =  []


    /**
     * resolve方法, 箭头函数可使resolve方法内部通过this获取到Promise实例
     * @param {*} value // 普通值或Promise对象
    */
    resolve = value=>{
        if( this.status !== PENDING) return  // 阻止非pending状态的prmise执行
        this.status = FULFILLED // 更改状态为成功
        this.value = value // 保存成功的值
        while (this.successCallback.length) {
            // 如果successCallback中有值，则按顺序将数组删除并将其返回值返回
            this.successCallback.shift()(this.value)
        }
    }

    /**
     * reject方法
     * @param {*} reason // 普通值或Promise对象
    */
    reject = reason=>{
        if( this.status !== PENDING) return // 阻止非pending状态的prmise执行
        this.status = REJECTED  // 更改状态为失败
        this.reason = reason  // 保存失败原因的值
        while (this.failCallback.length) {
            // 如果failCallback中有值，则按顺序将数组删除并将其返回值返回
            this.failCallback.shift()(this.reason)
        }
    }

    
    /**
     * then方法
     * @param {*} sucessCallback //成功的回调，非必传
     * @param {*} failCallback //失败的回调，非必传
     */
    then = (successCallback, failCallback) => {
        /** 链式调用时除非手动更改返回值，否则则需要将当前promise实例中的值传递下去 */
        successCallback = successCallback ? successCallback : value => value  
        failCallback = failCallback ? failCallback : reason=> { throw reason }

        /** 链式调用，让then方法返回一个promise对象 */
        let curPromise = new MyPromise((resolve, reject)=>{
            if( this.status ===FULFILLED){  // 状态成功时执行
                /** 通过异步执行, 才可获取到当前的promise, 并对异常进行捕获 */
                setTimeout(()=>{
                    try {
                        /** 将上一个的then方法作为下一个then方法的value */
                        let x =  successCallback(this.value)
                        resolvePromise(curPromise, x, resolve, reject)
                    } catch (error) {
                        reject(error) //捕获当前MyPromise实例对象上的错误
                    }
                  
                },0)
            }else if(this.status ===REJECTED){  // 状态失败时执行
                /** 通过异步执行, 才可获取到当前的promise, 并对异常进行捕获 */
                setTimeout(()=>{
                    try {
                        let x = failCallback(this.reason)
                        resolvePromise(curPromise, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)
            }else{  // 等待状态时执行
                /**
                 * 将成功回调和失败回调存储起来
                 * 通过异步执行, 才可获取到当前的promise
                 * 需进行异常捕获
                 */
                this.successCallback.push(()=>{
                    setTimeout(()=>{
                        try {
                            let x =  successCallback(this.value)
                            resolvePromise(curPromise, x, resolve, reject)
                        } catch (error) {
                            reject(error) //捕获当前MyPromise实例对象上的错误
                        }
                      
                    },0)
                })
                this.failCallback.push(()=>{
                    setTimeout(()=>{
                        try {
                            let x = failCallback(this.reason)
                            resolvePromise(curPromise, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    },0)
                })
            }
        })
        return curPromise
    }

    
     /**
     * 静态方法resolve， 最终返回一个promise实例
     * @param {*} value // 普通值或Promise对象
    */
    static resolve (value){
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve=>resolve(value))
    }


       
     /**
     *  静态方法reject，最终返回一个promise实例
     * @param {*} reason // 普通值或Promise对象
    */
    static reject (reason){
        if(reason instanceof MyPromise) return reason
        return new MyPromise(()=>{throw reason})
    }

         
    /**
     * 回调方法finally
     * @param {*} callback //该方法需要立即执行
     */
    finally = callback => {
        /** 允许fianlly返回值并进行回调 */
        return this.then(value=>{
            return MyPromise.resolve(callback()).then(()=>value)
        }, reason=>{
            return MyPromise.resolve(callback()).then(()=>{throw reason})
        })
    }

    /**
     * 回调函数catch，获取promis实例中每个环节的错误
     * @param {*} failCallback //失败回调
     */
    catch = failCallback => {
        return this.then(undefined, failCallback )
    }


    /**
     * 静态方法all
     * @param {*} array //promise || 普通值
     */
    static all (array) {
        let results = [] //存储array每个元素
        let index = 0 //记录执行array个数
        return new MyPromise((resolve, reject)=>{
            function addData  (key, value){
                results[key] = value
                index ++
                // 判断array的长度是否和执行的长度相等， 防止prmise中的异步操作未完成前就返回
                if(index === array.length){
                    resolve(results)
                }
            }
            for(let i = 0 ; i < array.length; i++){
                const current = array[i]
                if(current instanceof MyPromise){  // promise实例
                    current.then(value=> addData(i, value) , reject)
                }else{  // 普通值
                    addData(i, current)
                }
            }
        })
    }

}


/**
 * 
 * @param {*} curPromise //当前then方法的promise实例
 * @param {*} x //回调函数返回值
 * @param {*} resolve // 成功的回调函数
 * @param {*} reject // 失败的回调函数
 */
// 判断 x 的值是普通对象还是promise对象
// 如果是普通对象 直接调用resolve
// 如果是promise对象 查看promise对象返回的结果
// 再根据promise对象返回的结果 决定调用resolve还是reject
function resolvePromise (curPromise, x, resolve, reject){
    // 判断回调的返回值是否为当前的promise，防止调用链循环
    if(curPromise ===  x) {
      return  reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
    } 

    // 如果回调返回的是一个promise对象，就需要通过then去进行回调
    // 如果是普通值的话就可以直接调用resolve方法
    if(x instanceof MyPromise ){
        x.then(resolve, reject)
    }else{
        resolve(x)
    }
}


// module.exports = MyPromise;


const promise = new MyPromise((resolve, reject)=>{
    setTimeout(()=>{
        // resolve('async promise success')
        reject('async promise fail')
    }, 2000)
    // resolve('promise success')
})

const promise1 = new MyPromise((resolve, reject)=>{
    // throw Error('promise1 executor error')
    resolve('promise1 success')
    // reject('promise1 failed')
})

function other (){
    return new MyPromise((resolve,reject)=>{
        resolve('other')
    })
}

// 基本功能, then / resolve / reject功能
// 判断返回的实例对象是不是自己有点问题
// promise.then(value=>{
//     console.log(value)
// }, reason=>{
//     console.log(reason)
// })

// then链式调用 / 捕获异常
// promise1
// .then(value=>{
//     // throw Error('this is a error')
//     console.log(value)
// }, reason=>{
//     console.log(reason)
// })
// .then(value=>{
//     console.log(value)
// }, reason=>{
//     console.log(reason)
// })


// 静态方法resolve / reject
// MyPromise.resolve('test resolve').then(value=>{
//     console.log('static resolve value:', value)
// })
// MyPromise.reject('test reject').then(value=>{
//     console.log('static resolve value:', value)
// }, reason=>{
//     console.log('static reject reason:', reason)
// })


// 回调方法finally 
// promise1.finally(()=>{
//     console.log('finally')
//     return promise
// }).then(value=>{
//     console.log('finally then',value)
// },reason=>{
//     console.log('finally reason',reason)
// })


// 回调方法catch
// promise1.then(value=>{
//     console.log('catch value',value)
// }).catch(reason=>{
//     console.log('catch reason', reason)
// })


// 静态方法all
MyPromise.all(['a', promise1, promise, other() ])
.then(value=>{
    console.log('all', value)
}).catch(reason=>{
    console.log('all reason', reason)
})